home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
pascal
/
eventq.exe
/
EVENTQ.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-07-13
|
10KB
|
280 lines
{****************************************************************************}
{ The $X compiler directive must be set so that we can use the MessageBox }
{ function without worrying about the result. Feel free to change any other }
{ compiler settings if you want. }
{****************************************************************************}
{$X+}
unit EventQ;
interface
uses Drivers,Objects,Views,MsgBox,App;
{****************************************************************************}
{ This is the type declaration for the event queue object itself. Unless you }
{ plan to significantly modify the functionality of this unit, you can }
{ pretty much ignore the internal implementation of TEventQueue. Do look at }
{ the Init and PutQ methods, however, so you can see how the possible error }
{ conditions are handled; you may need to modify the implementation of these }
{ methods for your own application. }
{****************************************************************************}
type
PEventQueue = ^TEventQueue;
TEventQueue = object (TObject)
QueuePtr: Pointer;
Head,Tail,Size: Word;
constructor Init (ASize: Word); { ASize is the length of the queue }
function Empty: Boolean; { return true if queue is empty }
function Full: Boolean; { return true if queue is full }
procedure PutQ (var Event: TEvent); { insert a new Event into the queue }
procedure GetQ (var Event: TEvent); { remove next Event from the queue }
destructor Done; virtual;
constructor Load (var S: TStream);
procedure Store (var S: TStream);
end;
{****************************************************************************}
{ TEventQueueApp is a simple descendant of TApplication which implements a }
{ TEventQueue-type event queue. You can substitute 'TEventQueueApp' for }
{ 'TApplication' in your program, and there will be no outward change in the }
{ program's functionality. However, you will have an additional method, }
{ PushKey (Event), at your disposal. Invoking this method will insert Event }
{ into the event queue. You can call this method from anywhere in your }
{ application, as desired. Event must contain the same information as an }
{ evKeyDown event. Strictly speaking, this unit only supports evKeyDown }
{ events; however, you can also push other types of events if you know what }
{ you are doing. Be aware that this might not always work as expected in all }
{ situations. }
{****************************************************************************}
PEventQApp = ^TEventQApp;
TEventQApp = object (TApplication)
EventQueue: TEventQueue;
constructor Init;
procedure PushKey (var Event: TEvent); virtual;
procedure PutEvent (var Event: TEvent); virtual;
procedure GetEvent (var Event: TEvent); virtual;
destructor Done; virtual;
constructor Load (var S: TStream);
procedure Store (var S: TStream);
end;
{****************************************************************************}
{ The following procedure is provided so that you may load and store your }
{ TEventQApp's to and from a stream. Call this procedure (probably in your }
{ application's Init method) before you attempt a Load or Store. }
{****************************************************************************}
procedure RegisterEventQ;
implementation
const
Pending: TEvent = (What: evNothing); { same as in APP.PAS }
{****************************************************************************}
{ The following constants may need to be changed, depending on your }
{ application. QueueSize must be set larger than the maximum number of }
{ keystrokes you expect to push onto the queue at one time. NEventQueue and }
{ NEventApp are the (arbitrary) object registration numbers for the object }
{ types defined in this unit. In the unlikely event that the numbers }
{ conflict with any others that you are using, you will have to change one }
{ or the other. }
{****************************************************************************}
QueueSize = 100;
NEventQueue = 31416;
NEventQApp = 27183;
{****************************************************************************}
{ TEventQueue.Init attempts to allocate space for the event queue. If there }
{ is not enough memory available, it pops up a message box to inform the }
{ user of the fact. You might want to handle the situation differently in }
{ your application. }
{****************************************************************************}
constructor TEventQueue.Init (ASize: Word);
begin
TObject.Init;
if MaxAvail < ASize * SizeOf (TEvent) then
begin
MessageBox ('Not enough memory to build event queue.',nil,
mfError + mfOkButton);
Fail;
end
else begin
GetMem (QueuePtr,ASize * SizeOf (TEvent));
Size := ASize;
Head := 0;
Tail := 0;
end;
end; {TEventQueue.Init}
function TEventQueue.Empty: Boolean;
begin
Empty := Head = Tail;
end; {TEventQueue.Empty}
function TEventQueue.Full: Boolean;
begin
Full := (Head = Tail + 1) or ((Head = 0) and (Tail = Size - 1));
end; {TEventQueue.Full}
{****************************************************************************}
{ If the event queue is full, PutQ simply ignores any attempt to add another }
{ event to the queue. This may or may not be acceptable in your application. }
{****************************************************************************}
procedure TEventQueue.PutQ (var Event: TEvent);
begin
PEvent (Ptr (Seg (QueuePtr^),
Ofs (QueuePtr^) + Tail * SizeOf (TEvent)))^ := Event;
Tail := (Tail + 1) mod Size;
end; {TEventQueue.PutQ}
procedure TEventQueue.GetQ (var Event: TEvent);
begin
Event := PEvent (Ptr (Seg (QueuePtr^),
Ofs (QueuePtr^) + Head * SizeOf (TEvent)))^;
Head := (Head + 1) mod Size;
end; {TEventQueue.GetQ}
destructor TEventQueue.Done;
begin
FreeMem (QueuePtr,Size * SizeOf (TEvent));
Size := 0;
Head := 0;
Tail := 0;
TObject.Done;
end; {TEventQueue.Done}
constructor TEventQueue.Load (var S: TStream);
begin
S.Read (QueuePtr,SizeOf (Pointer));
S.Read (Head,SizeOf (Word));
S.Read (Tail,SizeOf (Word));
S.Read (Size,SizeOf (Word));
end; {TEventQueue.Load}
procedure TEventQueue.Store (var S: TStream);
begin
S.Write (QueuePtr,SizeOf (Pointer));
S.Write (Head,SizeOf (Word));
S.Write (Tail,SizeOf (Word));
S.Write (Size,SizeOf (Word));
end; {TEventQueue.Store}
constructor TEventQApp.Init;
begin
TApplication.Init;
if not EventQueue.Init (QueueSize) then Fail;
end; {TEventQApp.Init}
procedure TEventQApp.PushKey (var Event: TEvent);
begin
if not EventQueue.Full then EventQueue.PutQ (Event);
end; {TEventQApp.PushKey}
{****************************************************************************}
{ The PutEvent and GetEvent methods are basically copied wholesale from }
{ APP.PAS; GetEvent is modified to grab a keystroke event from the event }
{ queue if one is available. Otherwise, both methods function identically to }
{ the ones in the App unit. It was necessary to copy PutEvent, even though }
{ it is not changed, because both it and GetEvent access the Pending }
{ variable, which is hidden in App's implementation section. }
{****************************************************************************}
procedure TEventQApp.PutEvent (var Event: TEvent);
begin
Pending := Event;
end; {TEventQApp.PutEvent}
procedure TEventQApp.GetEvent (var Event: TEvent);
function ContainsMouse (P:PView): Boolean; far;
begin
ContainsMouse := (P^.State and sfVisible <> 0) and
P^.MouseInView (Event.Where);
end;
begin
if Pendin